//-------------------------------------------

(function($) {
	/* Wrapper for make draggable objects */
	$.fn.makeGraphElement = function() {
		var element = this.clone();
		element.children().filter("[name='drag_area']").bind({
			"mousedown": draggable_mousedownHandler,
			"mouseup": draggable_mouseupHandler});
		
		element.children().filter("[name='connect_area']").bind({
			"mousedown": connect_mousedownHandler,
			"mouseup": connect_mouseupHandler});
		
		var nodeOffset = window.graph.getNodeOffset();
		element = element.unselectable().css({"left": "" + nodeOffset + "px", "top": "" + nodeOffset + "px"}).bind({
			"click": draggable_clickHandler
		}).addClass("draggable").appendTo("#graph_field");
		
		var w = element.width();
		var h = element.height();
		window.graph.updateGraphSize(w + nodeOffset, h + nodeOffset);
		
		return element;
	};
	
	/* Unselect all graph items */
	$.graphUnselectAll = function() {
		$("#graph_field>.selected").graphUnselect();
	};
	
	/* Wrapper for select graph items */
	$.fn.graphSelect = function() {
		return this.each(function() {window.graph.select(this);});
	};
	
	/* Wrapper for unselect graph items */
	$.fn.graphUnselect = function() {
		return this.each(function() {window.graph.unselect(this);});
	};
	
	/* Wrapper for target graph items */
	$.fn.graphTarget = function() {
		return this.each(function() {window.graph.target(this);});
	};
	
	/* Wrapper for untarget graph items */
	$.fn.graphUntarget = function() {
		return this.each(function() {window.graph.untarget(this);});
	};
	
	/* Make element unselectable */
	$.fn.unselectable = function() {
		var children = this.children();
		if (children.length > 0)
			children.unselectable();
		return this.css({
			"-moz-user-select": "none",
			"-khtml-user-select": "none",
			"-webkit-user-select": "none",
			"-ms-user-select": "none",
			"user-select": "none"
		}).attr("unselectable", "on").on('selectstart dragstart', function(event) {
			event.preventDefault();
			return false;
		});
	};
})(jQuery);

//-------------------------------------------

/* Graph processor */
function Graph() {
	this.graphWidth = 0;
	this.graphHeight = 0;
	this.resize = null;
};

/* Graph node minimum side offset */
Graph.prototype.getNodeOffset = function() {
	return 50;
};

/* Select item */
Graph.prototype.select = function(item) {
	$(item).css("border-color", "#ff0000").addClass("selected");
};

/* Unselect item */
Graph.prototype.unselect = function(item) {
	$(item).css("border-color", "").removeClass("selected");
};

/* Start drag process */
Graph.prototype.startDrag = function(items) {
	items.each(function() {
		var self = $(this);
		pos = self.position();
		self.data("startDragPosition", pos);
	});
};

/* Stop drag process */
Graph.prototype.stopDrag = function(items) {
	items.removeData("startDragPosition");
};

/* Drag process */
Graph.prototype.doDrag = function(items) {
	
};

/* Start connection process */
Graph.prototype.startConnect = function(item) {
	
};

/* Finish connection process, item == null for fail */
Graph.prototype.stopConnect = function(item) {
	
};

/* Connection process in progress */
Graph.prototype.doConnect = function(target) {
	var position;
	if (target instanceof HTMLElement) {
		// Over node
		var p = $(target).position();
		position = {x: p.left, y: p.top + $(target).height() / 2};
		
	}
	else {
		// Over empty place
		position = target;
		
	}
	
	console.log("x="+position.x+";y="+position.y);
};

/* Target item for connect */
Graph.prototype.target = function(item) {
	$(item).css("border-color", "#00ff00").addClass("targeted");
};

/* Untarget previous targeted item */
Graph.prototype.untarget = function(item) {
	$(item).css("border-color", "").removeClass("targeted");
};

/* Update graph size, get bottom right bounding box for modified elements */
Graph.prototype.updateGraphSize = function(right, bottom) {
	var isResize = false;
	if (right > this.graphWidth) {
		this.graphWidth = right;
		isResize = true;
	}
	if (bottom > this.graphHeight) {
		this.graphHeight = bottom;
		isResize = true;
	}
	
	if (isResize && this.resize)
		this.resize(this.graphWidth, this.graphHeight);
};

//-------------------------------------------

/* Draggable element click handler */
function draggable_clickHandler(event) {
	if (!event.shiftKey)
		$.graphUnselectAll();
	$(this).graphSelect();
	return false;
}

/* Draggable element mouse down handler */
function draggable_mousedownHandler(event) {
	var item = $(this).closest(".draggable");
	if (event.shiftKey) {
		item.graphSelect();
	}
	else {
		var selItemsCount = $("#graph_field>.selected").length;
		if (selItemsCount <= 1) {
			if (selItemsCount == 1)
				$.graphUnselectAll();
			item.graphSelect();
		}
	}
	
	$("#scroller").bind({
		"mousemove": draggable_mousemoveHandler,
		"mouseleave": draggable_mouseupHandler,
		"mouseup": draggable_mouseupHandler
	});
}

/* Draggable element mouse up handler */
function draggable_mouseupHandler(event) {
	var item = $(this).closest(".draggable");
	if (window.startDragMousePosition) {
		// Stop drag
		delete window.startDragMousePosition;
		window.graph.stopDrag($("#graph_field>.selected"));
	}
	
	$("#scroller").unbind({
		"mousemove": draggable_mousemoveHandler,
		"mouseleave": draggable_mouseupHandler,
		"mouseup": draggable_mouseupHandler
	});
}

/* Draggable mouse move handler */
function draggable_mousemoveHandler(event) {
	var right = 0;
	var bottom = 0;
	var startPos = window.startDragMousePosition;
	if (startPos) {
		// Drag
		var nodeOffset = window.graph.getNodeOffset();
		var currentPos = {left: event.pageX, top: event.pageY};
		window.graph.doDrag($("#graph_field>.selected").each(function() {
			var self = $(this);
			var p = self.data("startDragPosition");
			if (p) {
				var left = p.left + currentPos.left - startPos.left;
				var top = p.top + currentPos.top - startPos.top;
				if (left < nodeOffset)
					left = nodeOffset;
				if (top < nodeOffset)
					top = nodeOffset;
				
				self.css({"left": "" + left + "px", "top": "" + top + "px"});
				
				var w = left + self.width();
				var h = top + self.height();
				
				if (w > right)
					right = w;
				if (h > bottom)
					bottom = h;
			}
		}));
		window.graph.updateGraphSize(right, bottom);
	}
	else {
		// Start drag
		window.startDragMousePosition = {left: event.pageX, top: event.pageY};
		window.graph.startDrag($("#graph_field>.selected"));
	}
}

/* Connect area mouse down handler */
function connect_mousedownHandler(event) {
	var item = $(this).closest(".draggable");
	$(".draggable").not(item).on({
		"mouseover": connect_mouseoverHandler,
		"mouseout": connect_mouseoutHandler,
		"mouseup": connect_mouseupHandler
	});
	
	$("#scroller").bind({
		"mousemove": connect_mousemoveHandler,
		"mouseleave": connect_mouseupHandler,
		"mouseup": connect_mouseupHandler
	});
	
	window.graph.startConnect(item);
}

/* Connect area mouse up handler */
function connect_mouseupHandler(event) {
	$(".draggable").off({
		"mouseover": connect_mouseoverHandler,
		"mouseout": connect_mouseoutHandler,
		"mouseup": connect_mouseupHandler
	}).graphUntarget();
	
	$("#scroller").unbind({
		"mousemove": connect_mousemoveHandler,
		"mouseleave": connect_mouseupHandler,
		"mouseup": connect_mouseupHandler
	});
	
	if ($(this).is("#scroller")) {
		// This is scroller, do nothing
		window.graph.stopConnect(null);
	}
	else {
		var item = $(this).closest(".draggable");
		window.graph.stopConnect(item);
	}
}

/* Mouse over node when connection in process */
function connect_mouseoverHandler(event) {
	$(this).closest(".draggable").graphTarget();
}

/* Mouse out node when connection in process */
function connect_mouseoutHandler(event) {
	$(this).closest(".draggable").graphUntarget();
}

/* Mouse out node when connection in process */
function connect_mousemoveHandler(event) {
	var target = $("#graph_field>.targeted");
	if (target.length > 0) {
		window.graph.doConnect(target[0]);
	}
	else {
		var position = $(this).position();
		var left = event.pageX - position.left;
		var top = event.pageY - position.top;
		if (left < 0)
			left = 0;
		if (top < 0)
			top = 0;
		window.graph.doConnect({x: left, y: top});
	}
}

/* Graph resize handler */
function graph_resizeHandler(width, height) {
	var nodeOffset = window.graph.getNodeOffset();
	$("#connect_view").css({"width": "" + (width + nodeOffset) + "px", "height": "" + (height + nodeOffset) + "px"});
}

//-------------------------------------------

/* Creation complete */
jQuery(function() {
	// Tool bar
	$(".toolSetItemClass").hover(function(){$(this).toggleClass("hover");});
	$("#tool_add_new").click(function(event) {$("div.templateSet>.beginTemplate").makeGraphElement();});
	
	// Graph
	window.graph = new Graph();
	window.graph.resize = graph_resizeHandler;
	var nodeOffset = window.graph.getNodeOffset();
	$("#scroller").click(function(event) {$.graphUnselectAll();});
	$("#connect_view").css({"width": "" + (nodeOffset * 2) + "px", "height": "" + (nodeOffset * 2) + "px"});
});

//-------------------------------------------

